/*
 *	Author: Karthic Kumar Sekar [A0092622] 
 */
package sg.edu.nus.iss.team4ft.service;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import sg.edu.nus.iss.team4ft.exception.InvalidOperationException;
import sg.edu.nus.iss.team4ft.util.AppConstant;
import sg.edu.nus.iss.team4ft.util.DateUtil;

public class Plan extends ServiceSubscription  implements Serializable {

	private static final long serialVersionUID = 1L;
	private PlanCode planCode;
	protected List<Feature> features = new ArrayList<Feature>();	
	
	protected Plan(Plan plan){
		super((ServiceSubscription)plan);
		this.planCode = plan.planCode;
		this.features = new ArrayList<Feature>(plan.features);
	}

	public Plan(Date startDate, PlanCode planCode){
		super(startDate);
		setPlanCode(planCode);
	}
	
	public void setPlanCode(PlanCode planCode) {
		this.planCode = planCode;
	}
	
	@Override
	public void setEndDate(Date endDate) throws InvalidOperationException {
		// TODO Auto-generated method stub
		super.setEndDate(endDate);
		
		for (Feature f : features) {
			if(f.getEndDate() == null)
				f.setEndDate(endDate);
		}
	}

	public PlanCode getPlanCode() {
		return this.planCode;
	}	
	
	public Feature getFeature(String featureName) throws CloneNotSupportedException{
		Feature feature = null;
		for (Feature f : features) {
			if(f.getServiceName().equals(featureName) && f.getEndDate() == null)
				feature = f.clone();			
		}
		return feature;
	}
	
	public void subscripeNewFeature(List<Feature> features){
		for (Feature feature : features) {
			feature.setPlan(this);
			if(feature.getIsDefaultService())
				feature.setStartDate(this.getStartDate());
			feature.setPlan(this);
		}
		features.addAll(features);
	}
	
	@Override
	public void unsubscribeService(Date unsubscriptionDate)
			throws InvalidOperationException {
		super.unsubscribeService(unsubscriptionDate);
		
		for (Feature f : features) {
			f.unsubscribeService(unsubscriptionDate);
		}
	}
	
	//A new Feature can be added only if
	//	Condition 1. No such Feature exist (or)
	//	Condition 2. A Feature of same type exist but it is unsubscripted
	public void subscripeNewFeature(Feature feature) throws InvalidOperationException{
		List<Feature> removeFeatures = new ArrayList<Feature>();	
		if(feature != null && features != null){
			
		//Feature start date cannot be before plan start date
		if(DateUtil.dateIsBefore(feature.getStartDate(), this.getStartDate()))
			throw(new InvalidOperationException(feature.getServiceName() + AppConstant.ACTIVATION_DATE_MSG_START + DateUtil.defaultFormat(feature.getStartDate()) 
					+ AppConstant.BEFORE_MSG + this.getServiceName() + " " + AppConstant.ACTIVATION_DATE_MSG_START + DateUtil.defaultFormat(this.getStartDate()) + "]."));
		
		//Feature end date cannot be after plan end date
		if(feature.getEndDate() != null && this.getEndDate() != null && DateUtil.dateIsBefore(this.getEndDate(), feature.getEndDate()))
			throw(new InvalidOperationException(feature.getServiceName() + AppConstant.DEACTIVATION_DATE_MSG_START + DateUtil.defaultFormat(feature.getStartDate()) 
					+ AppConstant.AFTER_MSG + this.getServiceName() + " " + AppConstant.DEACTIVATION_DATE_MSG_START + DateUtil.defaultFormat(this.getStartDate()) + "]."));
		
			for (Feature f : features) {
				if(f.getServiceId() == feature.getServiceId())//if(f.getServiceName() == feature.getServiceName() && !f.canInclude(feature))
					removeFeatures.add(f);
			}
		features.removeAll(removeFeatures);
		
		if(feature.getIsDefaultService())
			feature.setStartDate(this.getStartDate());

		feature.setPlan(this);
		features.add(feature);
		}
	}
	
	//When ever plan start date changes, 
	//corresponding default feature start date must be assigned with same date
	@Override
	public void setStartDate(Date startDate) {
		super.setStartDate(startDate);
		if(features!= null)
		for (Feature f : features) {
			if(f.getIsDefaultService())
				f.setStartDate(this.getStartDate());
		}
	}
	
	//When a customer is deactivated on current date,
	//set remove feature with future date
	public void setFeatureStartDateOnDeactivation() {
		List<Feature> removeFeatures = new ArrayList<Feature>();
		if(features!= null)
		for (Feature f : features) {
			if(!DateUtil.dateIsBefore(f.getStartDate(), DateUtil.getDate()))
				removeFeatures.add(f);
		}
		features.removeAll(removeFeatures);
	}
	
	//A new plan can be added only if
	//	Condition 1. No such plan exist (or)
	//	Condition 2. A plan of same type exist but it is unsubscripted
	@Override
	public boolean canInclude(ServiceSubscription service) {
		boolean canInclude = super.canInclude(service);
		
		if(service instanceof Plan)
		{
			Plan p = (Plan)service;
			//check condition 2 stated above
			if(this.planCode == p.planCode && this.isSubscriptionActive(DateUtil.getDate()) && p.getEndDate() == null)
			{
				canInclude = false;
			}
		}
		return canInclude;
	}

	public Feature getFeature(FeatureCode featureCode) throws CloneNotSupportedException{
		Feature feature = null;
		for (Feature f : features) {
			if(f.getFeatureCode() == featureCode && f.getEndDate() == null)
				feature = f.clone();			
		}
		return feature;
	}

	public List<Feature> getFeatures() throws CloneNotSupportedException {
		return new ArrayList<Feature>(features);
	}
	
	public boolean equals(PlanCode planCode){
		if (this.planCode == planCode){
			return true;
		}else{
			return false;
		}
	}
	
	public boolean equals(Plan plan){
		if (this.planCode == plan.planCode){
			return true;
		}else{
			return false;
		}
	}
	@Override
	public Plan clone() throws CloneNotSupportedException {
		Plan p = new Plan(this);
		return p;
	}

	//This will be called by only at the time of bill calculation.
	//If same plan exist for single month, subcription charge is applicable for only one plan.
	//so for the other plan, set it to zero.
	//but, call charge is applicable
	public void setFeatureSubcriptionChargeToZero() {
		for (Feature f : features) {
			f.setSubscriptionCharge(0.0);
		}		
	}
}

